import { useRouter } from "next/router";
import { SWRConfiguration } from "swr";
import { useMemo, useEffect, useRef, useState, useCallback } from "react";
import {
  PaginatedProjectsResponse,
  ProjectDetails,
  operations,
} from "generatedApi";
import { useGlobalLocalStorage } from "@common/lib/useGlobalLocalStorage";
import { useDebounce } from "react-use";
import { createInfiniteHook } from "swr-openapi";
import { useAuthHeader } from "hooks/fetching";
import flatMap from "lodash/flatMap";
import { useCurrentTeam } from "./teams";
import { useBBMutation, useBBQuery, client } from "./api";

const useInfinite = createInfiniteHook(client, "big-brain");

export function useCurrentProject() {
  const team = useCurrentTeam();
  const { query } = useRouter();
  const { project: projectSlug } = query;
  return useProjectBySlug(team?.id, projectSlug as string);
}

export function useProjectById(projectId: number | undefined) {
  const { data } = useBBQuery({
    path: "/projects/{project_id}",
    pathParams: {
      project_id: projectId?.toString() || "",
    },
  });
  return data;
}

export function useProjectBySlug(
  teamId: number | undefined,
  projectSlug: string | undefined,
) {
  const { data, isLoading } = useBBQuery({
    path: "/teams/{team_id}/projects/{project_slug}",
    pathParams: {
      team_id: teamId || 0,
      project_slug: projectSlug || "",
    },
  });
  if (isLoading) {
    return undefined;
  }
  return data;
}

export function usePaginatedProjects(
  teamId: number | undefined,
  options: {
    cursor?: string;
    q?: string;
    limitOverride?: number;
  },
  refreshInterval?: SWRConfiguration["refreshInterval"],
): (PaginatedProjectsResponse & { isLoading: boolean }) | undefined {
  const [pageSize] = useGlobalLocalStorage("projectsPageSize", 25);

  const queryParams = useMemo(
    () =>
      ({
        cursor: options.cursor,
        limit: options.limitOverride || pageSize,
        q: options.q,
      }) satisfies operations["get_projects_for_team"]["parameters"]["query"],
    [options, pageSize],
  );

  const { data, isLoading } = useBBQuery({
    path: "/teams/{team_id}/projects",
    pathParams: {
      team_id: teamId?.toString() || "",
    },
    queryParams,
    swrOptions: { refreshInterval },
  });

  if (data === undefined) {
    return undefined;
  }

  // If it's an array (simple response), convert to paginated format
  if (Array.isArray(data)) {
    return {
      items: data,
      pagination: {
        hasMore: false,
      },
      isLoading,
    };
  }

  return { ...data, isLoading };
}

// Returns all projects (unpaginated) - for backward compatibility
export function useProjects(
  teamId: number | undefined,
  refreshInterval?: SWRConfiguration["refreshInterval"],
): ProjectDetails[] | undefined {
  const { data: allProjects } = useBBQuery({
    path: "/teams/{team_id}/projects",
    pathParams: {
      team_id: teamId?.toString() || "",
    },
    swrOptions: { refreshInterval },
  });

  if (allProjects === undefined) {
    return undefined;
  }

  if (!Array.isArray(allProjects)) {
    throw new Error("Expected array of projects");
  }

  return allProjects;
}

/**
 * Hook for infinite scroll pagination of projects with search support
 * Returns paginated projects data with loading state and pagination controls
 */
export function useInfiniteProjects(teamId: number, searchQuery: string = "") {
  const authHeader = useAuthHeader();
  const [pageSize] = useGlobalLocalStorage("projectsPageSize", 25);
  const [debouncedQuery, setDebouncedQuery] = useState("");

  // Debounce search query (300ms delay)
  useDebounce(
    () => {
      setDebouncedQuery(searchQuery);
    },
    300,
    [searchQuery],
  );

  const { data, isLoading, setSize } = useInfinite(
    "/teams/{team_id}/projects",
    (
      pageIndex: number,
      previousPageData: PaginatedProjectsResponse | null,
    ): any => {
      // Stop if we've reached the end (but allow first page)
      if (
        pageIndex > 0 &&
        previousPageData &&
        !previousPageData.pagination.hasMore
      ) {
        return null;
      }

      return {
        headers: {
          Authorization: authHeader,
          "Convex-Client": "dashboard-0.0.0",
        },
        params: {
          path: {
            team_id: teamId.toString(),
          },
          query: {
            limit: pageSize,
            cursor:
              pageIndex > 0 && previousPageData
                ? previousPageData.pagination.nextCursor
                : undefined,
            ...(debouncedQuery.trim() ? { q: debouncedQuery.trim() } : {}),
          },
        },
      };
    },
  );

  // Manual reset when query changes
  const prevQuery = useRef(debouncedQuery);
  useEffect(() => {
    if (prevQuery.current !== debouncedQuery) {
      prevQuery.current = debouncedQuery;
      void setSize(1);
    }
  }, [debouncedQuery, setSize]);

  const projects = useMemo(
    () => flatMap(data?.map((page) => page.items)),
    [data],
  );

  const hasMore = data?.[data.length - 1]?.pagination.hasMore ?? false;

  const loadMore = useCallback(() => {
    if (hasMore && !isLoading) {
      void setSize((prevSize) => prevSize + 1);
    }
  }, [hasMore, isLoading, setSize]);

  return {
    projects,
    isLoading,
    hasMore,
    loadMore,
    debouncedQuery,
    pageSize,
  };
}

export function useCreateProject(teamId?: number) {
  return useBBMutation({
    path: "/create_project",
    pathParams: undefined,
    mutateKey: "/teams/{team_id}/projects",
    mutatePathParams: {
      team_id: teamId?.toString() || "",
    },
    googleAnalyticsEvent: "create_project_dash",
  });
}

export function useUpdateProject(projectId: number) {
  return useBBMutation({
    path: "/projects/{project_id}",
    pathParams: {
      project_id: projectId.toString(),
    },
    successToast: "Project updated.",
    method: "put",
  });
}

export function useDeleteProject(
  teamId?: number,
  projectId?: number,
  projectName?: string,
) {
  return useBBMutation({
    path: "/delete_project/{project_id}",
    pathParams: {
      project_id: projectId?.toString() || "",
    },
    mutateKey: "/teams/{team_id}/projects",
    mutatePathParams: {
      team_id: teamId?.toString() || "",
    },
    successToast: projectName ? `Deleted project: ${projectName}.` : undefined,
    redirectTo: "/",
  });
}

export function useDeleteProjects(teamId: number | undefined) {
  return useBBMutation({
    path: "/delete_projects",
    pathParams: undefined,
    mutateKey: "/teams/{team_id}/projects",
    mutatePathParams: {
      team_id: teamId?.toString() || "",
    },
    successToast: "Projects deleted.",
  });
}
